package medusa

import (
	"fmt"
	"net"
	"sync/atomic"
	"time"
)

//socket逻辑evp
//socket-join
//socket sent chan不要关闭，只是清空

//dispatch_event/push_event <->event_callback/event_handler
//medusa-yasm模板：new、newclass
//const IDLE_MS_MIN_VALUE = 10000 // 10秒IDLE_MS_MIN_VALUE  = 10000// 10秒
const (
	//其他常量
	MIN_IDLE_SEC     int64 = 1
	REMOTE_CHECK_ADD int64 = 5
)

//检查：本地空闲处理+远程心跳
type Socket struct {
	HasLog
	StateCounter
	Tasklet

	uuid int
	fd   *net.TCPConn

	rcv_buf         int
	snd_buf         int
	sndchan         int
	sent_chan       chan *Packet
	sent_chan_state StateCounter

	ringbuf          *ByteBuffer
	rcvbuf           []byte
	half_packet_recv interface{}

	max_idle_sec                int64
	heartbeat_begin_time_remote int64 //last_active_time_remote
	heartbeat_begin_time_local  int64 //last_active_time_local

	handler map[int]func(pack *Packet)

	ecb_idle        func()
	ecb_pre_sent    func(pack *Packet)
	ecb_conn_lose   func()
	ecb_unknow_data func(pack *Packet)
}

func (self *Socket) constructor(name string, uuid int, max_idle_sec int64, rcv_buf int, snd_buf int, sndchan int, log Log,
	ecb_idle func(),
	ecb_pre_sent func(pack *Packet),
	ecb_conn_lose func(),
	ecb_unknow_data func(pack *Packet)) {

	self.uuid = uuid
	self.max_idle_sec = max_idle_sec
	self.rcv_buf = rcv_buf
	self.snd_buf = snd_buf
	self.sndchan = sndchan
	self.ecb_conn_lose = ecb_conn_lose
	self.ecb_idle = ecb_idle
	self.ecb_pre_sent = ecb_pre_sent
	self.ecb_unknow_data = ecb_unknow_data

	self.ringbuf = NewByteBuffer()
	self.rcvbuf = make([]byte, rcv_buf)

	self.sent_chan = make(chan *Packet, sndchan)

	self.half_packet_recv = nil
	self.handler = make(map[int]func(pack *Packet))
	self_name := fmt.Sprintf("%v-%v:", name, self.uuid)
	self.Tasklet.Constructor(self_name)
	self.HasLog.Constructor(self_name, log)

	self.AddMethod("acc-idle", func(args ...interface{}) (result interface{}, err error) {
		self.ecb_idle()
		return
	})

	self.AddMethod("acc-data-recv", func(args ...interface{}) (result interface{}, err error) {
		pack := args[0].(*Packet)
		if pack != nil {
			ev_callback := self.handler[(int)(pack.Des)]
			if ev_callback != nil {
				ev_callback(pack)
			} else if self.ecb_unknow_data != nil {
				self.ecb_unknow_data(pack)
			}
		}
		return
	})

	self.AddMethod("acc-add-protocol", func(args ...interface{}) (result interface{}, err error) {
		des := args[0].(int)
		proc := args[1].(func(pack *Packet))
		self.handler[des] = proc
		result = true
		return
	})

	self.AddMethod("acc-startup", func(args ...interface{}) (result interface{}, err error) {
		fd := args[0].(*net.TCPConn)
		self.ringbuf.Reset()
		self.fd = fd
		self.fd.SetReadBuffer(self.rcv_buf)
		self.fd.SetWriteBuffer(self.snd_buf)
		self.start_io_thread()
		return
	})

	self.AddMethod("acc-release", func(args ...interface{}) (result interface{}, err error) {
		self.fd.Close()
		self.ecb_conn_lose()
		self.Error("socket release!(uuid:<%d>: %v <- %v)", self.GetUUID32(), self.GetLocalAddr(), self.GetRemoteAddr())
		return
	})
}

///////////////////////////////////////////////////////////////////////////////////////
//抛出事件

func (self *Socket) startup(fd *net.TCPConn) {
	if self.SwicthWorking() {
		self.CallMethod("acc-startup", fd)
	}
}

func (self *Socket) SendPacket(pack *Packet) {
	if pack != nil && self.IsWorking() {
		self.sent_chan <- pack
	}
}

func (self *Socket) AddProtocol(des int, proc func(pack *Packet)) bool {
	ret := false
	if proc != nil {
		val, _ := self.CallMethod("acc-add-protocol", des, proc)
		ret = val.(bool)
	}
	return ret
}

func (self *Socket) Close() {
	self.Error("local close.")
	if self.SwicthClosed() {
		if self.sent_chan_state.SwicthClosed() {
			self.sent_chan <- nil
		}
		self.CallMethod("acc-release")
	}
}

func (self *Socket) shutdown() {
	self.Close()
	self.Tasklet.shutdown()
}

///////////////////////////////////////////////////////////////////////////////////////
//其他
func (self *Socket) GetFD() *net.TCPConn {
	return self.fd
}

func (self *Socket) GetUUID() int {
	return self.uuid
}

func (self *Socket) GetUUID32() int32 {
	return (int32)(self.uuid)
}

func (self *Socket) GetLocalAddr() net.Addr {
	return self.fd.LocalAddr()
}

func (self *Socket) GetRemoteAddr() net.Addr {
	return self.fd.RemoteAddr()
}

func (self *Socket) start_io_thread() {

	self.local_idle_reset()
	self.remote_heartbeat_active()

	//read thread
	go func() {
		self.Add(1)
		self.Error("-->recv thread work!(uuid:<%d>: %v <- %v)", self.GetUUID32(), self.GetLocalAddr(), self.GetRemoteAddr())
		for self.IsWorking() {

			received, err := self.fd.Read(self.rcvbuf[:])

			if err != nil {
				self.Error("recv thread: %v", err.Error())
				self.Close()
				break
			}

			if received <= 0 {
				self.Error("remote disconnect!")
				self.Close()
				break
			}
			self.ringbuf.Write(self.rcvbuf[0:received])

			for {
				pack := self.parse_packet()
				if pack == nil {
					break
				} else {
					self.remote_heartbeat_active()
					self.CallMethod("acc-data-recv", pack)
				}
			} //end: for
			//runtime.Gosched()
		} //end: for

		self.Error("-->recv thread free!(uuid:<%d>: %v <- %v)",
			self.GetUUID32(), self.GetLocalAddr(), self.GetRemoteAddr())
		self.Done()
	}()

	//sent thread
	go func() {
		if self.sent_chan_state.SwicthWorking() {
			self.Add(1)
			self.Error("-->sent thread work!(uuid:<%d>: %v <- %v)",
				self.GetUUID32(), self.GetLocalAddr(), self.GetRemoteAddr())
			for { //不能在这里判断IsWorking的原因：要让发送队列清空
				pack := <-self.sent_chan
				if pack == nil {
					break
				}
				if self.IsWorking() { //就算不运行了，也要让发送队列清空
					if self.ecb_pre_sent != nil {
						self.ecb_pre_sent(pack)
					}
					err := pack.Write2IO(self.fd)
					if err != nil {
						self.Error("send thread:" + err.Error())
						self.Close()
					} else {
						self.local_idle_reset()
					}
				}

			} //end: for
		} //end: if self.sent_chan_state.SwicthWorking()

		self.Error("-->sent thread free!(uuid:<%d>: %v <- %v)",
			self.GetUUID32(), self.GetLocalAddr(), self.GetRemoteAddr())
		self.sent_chan_state.SwicthClosed()
		self.Done()
	}()

	//idle
	if self.max_idle_sec >= MIN_IDLE_SEC {
		go func() {
			self.Add(1)
			self.Error("-->idle thread is work!(uuid:<%d>: %v <- %v)", self.GetUUID32(), self.GetLocalAddr(), self.GetRemoteAddr())
			for self.IsWorking() && self.remote_heartbeat_check() {
				self.local_idle_check()
				time.Sleep(1000 * time.Millisecond)
			}
			self.Error("-->idle thread is free!(uuid:<%d>: %v <- %v)", self.GetUUID32(), self.GetLocalAddr(), self.GetRemoteAddr())
			self.Done()
		}()
	}

}

func (self *Socket) remote_heartbeat_active() {
	atomic.StoreInt64(&self.heartbeat_begin_time_remote, time.Now().Unix())
}

func (self *Socket) remote_heartbeat_check() bool {
	is_die := (time.Now().Unix() - atomic.LoadInt64(&self.heartbeat_begin_time_remote)) > (self.max_idle_sec + REMOTE_CHECK_ADD)
	if is_die {
		self.Error("$$$ remote silent time > %d seconds, already death! $$$",
			(self.max_idle_sec + REMOTE_CHECK_ADD))
		self.Close()
	}
	return !is_die
}

func (self *Socket) local_idle_reset() {
	atomic.StoreInt64(&self.heartbeat_begin_time_local, time.Now().Unix())
}

func (self *Socket) local_idle_check() {
	max_idle := (time.Now().Unix()-atomic.LoadInt64(&self.heartbeat_begin_time_local) >= self.max_idle_sec)
	// 达到最大空闲时间,必须进行空闲处理
	if max_idle {
		self.Debug("local max idle! (uuid:<%d>: %v <- %v)", self.GetUUID32(), self.GetLocalAddr(), self.GetRemoteAddr())
		self.CallMethod("acc-idle")
	}
}

func (self *Socket) parse_packet() *Packet {

	if self.ringbuf.Len() <= 0 {
		return nil
	}

	var pack *Packet = nil

	if self.half_packet_recv == nil {
		if self.ringbuf.Len() >= PACKET_HEAD_LEN {
			m := self.ringbuf.ReadByte()
			a := self.ringbuf.ReadInt16LE()
			b := self.ringbuf.ReadInt16LE()
			c := self.ringbuf.ReadUint16LE()
			length := self.ringbuf.ReadInt32LE()
			msgcode := self.ringbuf.ReadUint16LE()
			session_or_space_id := self.ringbuf.ReadInt32LE()
			is_space_msg := (self.ringbuf.ReadInt8() == 1)
			except_uuid := self.ringbuf.ReadInt32LE()
			notify_or_result := self.ringbuf.ReadInt32LE()
			timestamp := self.ringbuf.ReadInt64LE()

			pack = NewRecvPacket(m, a, b, c, length, msgcode, session_or_space_id, is_space_msg, except_uuid, notify_or_result, timestamp)
			if self.ringbuf.Len() >= (pack.PacketSize() - PACKET_HEAD_LEN) {
				pack.ReadBufferFromReader(self.ringbuf, (pack.PacketSize() - PACKET_HEAD_LEN))
				//pack.Trace("Acceptor--PacketReceived")
			} else {
				self.half_packet_recv = pack
				pack.ReadBufferFromReader(self.ringbuf, self.ringbuf.Len())
				pack = nil
			}
		}

	} else {
		pack = self.half_packet_recv.(*Packet)
		var residual int = pack.PacketSize() - pack.DataSize()

		if self.ringbuf.Len() >= residual {
			pack.ReadBufferFromReader(self.ringbuf, residual)
			self.half_packet_recv = nil
			//pack.Trace("Acceptor--PacketReceived")
		} else {
			pack.ReadBufferFromReader(self.ringbuf, self.ringbuf.Len())
			pack = nil
		}
	}

	return pack
}
